package com.niknik.woody.rest.guice;

import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import com.google.inject.Singleton;
import com.niknik.woody.core.ServerToClientTransmitter;
import com.niknik.woody.core.room.Room;
import com.niknik.woody.core.room.RoomRegistry;
import com.niknik.woody.rest.RestTestContext;
import com.niknik.woody.rest.rule.MainRoomRestClient;
import com.niknik.woody.rest.rule.ResLogMonitor;
import com.niknik.woody.utils.wunit.junit.rule.AfterTestVerifier;
import org.mockito.InOrder;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

import java.util.logging.Handler;

import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.*;

public class RestTestModule
    extends AbstractModule {

  @Override
  protected void configure() {
    bind(MainRoomRestClient.class).in(Singleton.class);
    bind(ResLogMonitor.class).in(Singleton.class);
    bind(AfterTestVerifier.class).in(Singleton.class);

    bind(RestTestContext.class).toInstance(new RestTestContext());
  }

  @Provides
  @Singleton
  public RoomRegistry getRoomRegistry(final RestTestContext context) {
    RoomRegistry roomRegistryMock = mock(RoomRegistry.class);

    when(roomRegistryMock.getRoomsSnapshot()).thenReturn(context.rooms);
    doReturn(context.newRoom).when(roomRegistryMock).create();
    when(roomRegistryMock.get(anyString())).thenAnswer(new Answer<Object>() {

      @Override
      public Object answer(InvocationOnMock invocation)
          throws Throwable {
        Long roomId = (Long) invocation.getArguments()[0];

        if (context.monitoredRoomId.equals(roomId)) {
          return context.monitoredRoom;
        }

        for (Room room : context.rooms) {
          if (room.getId().equals(roomId)) {
            return room;
          }
        }
        return null;
      }
    });

    return roomRegistryMock;
  }

  @Provides
  @Singleton
  public ServerToClientTransmitter getServerToClientTransmitter(RestTestContext context) {
    ServerToClientTransmitter mock = mock(ServerToClientTransmitter.class);
    when(mock.createChannel(anyString(), eq(context.playerId))).thenReturn(context.roomToken);
    return mock;
  }

  @Provides
  @Singleton
  public InOrder getInOrder(ServerToClientTransmitter serverToClientTransmitterMock, RoomRegistry roomRegistryMock,
                            Handler logHandlerMock, RestTestContext context) {
    return Mockito.inOrder(serverToClientTransmitterMock, roomRegistryMock, logHandlerMock, context.monitoredRoom);
  }

  @Provides
  @Singleton
  public Handler getLogHandler() {
    return mock(Handler.class);
  }
}
